using System;
using System.Collections;
using System.Diagnostics;
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Schema;

namespace Vibstudio.X4NET.Xml.Generation
{
    #region Namespaces

    

    #endregion

    internal enum AddSubtractState
    {
        StartPlusInc = 0,

        StartMinusInc = 1,

        MaxMinusInc = 2,

        MinPlusInc = 3,
    }

    internal abstract class XmlValueGenerator
    {
        #region Static Fields

        internal static readonly XmlValueGenerator AnyGenerator = new GeneratorAnyType();

        internal static readonly XmlValueGenerator AnySimpleTypeGenerator = new GeneratorAnySimpleType();

        internal static readonly GeneratorID GeneratorID = new GeneratorID();

        internal static readonly GeneratorIDREF GeneratorIDREF = new GeneratorIDREF();

        internal static readonly ArrayList Ids = new ArrayList();

        internal static readonly AddSubtractState[] States =
            {
                AddSubtractState.StartPlusInc,
                AddSubtractState.MinPlusInc, AddSubtractState.MaxMinusInc
                , AddSubtractState.StartMinusInc
            };

        internal static readonly Type TypeOfString = typeof(String);

        internal static int IDCnt;

        internal static bool IDRef;

        #endregion

        #region Fields

        protected ArrayList AllowedValues;

        protected int OccurNum;

        #endregion

        #region Public Properties

        public virtual string Prefix { get; set; }

        #endregion

        #region Properties

        internal static ArrayList IDList
        {
            get { return Ids; }
        }

        protected XmlSchemaDatatype Datatype { get; private set; }

        #endregion

        #region Public Methods and Operators

        public virtual void AddGenerator(XmlValueGenerator genr)
        {
        }

        public abstract string GenerateValue();

        #endregion

        #region Methods

        internal static XmlValueGenerator CreateGenerator(XmlSchemaDatatype datatype, int listLength)
        {
            XmlTypeCode typeCode = datatype.TypeCode;

            object restriction = datatype.GetType()
                                         .InvokeMember("Restriction",
                                                       BindingFlags.GetProperty | BindingFlags.NonPublic |
                                                       BindingFlags.Instance,
                                                       null,
                                                       datatype,
                                                       null);
            var rFacets = new CompiledFacets(restriction);
            XmlValueGenerator generator;

            if (datatype.Variety == XmlSchemaDatatypeVariety.Union)
            {
                generator = CreateUnionGenerator(datatype, rFacets, listLength);
            }
            else if (datatype.Variety == XmlSchemaDatatypeVariety.List)
            {
                generator = CreateListGenerator(datatype, rFacets, listLength);
            }
            else
            {
                switch (typeCode)
                {
                    case XmlTypeCode.None:
                        generator = AnyGenerator;
                        break;
                    case XmlTypeCode.Item:
                        generator = AnyGenerator;
                        break;
                    case XmlTypeCode.AnyAtomicType:
                        generator = AnySimpleTypeGenerator;
                        break;
                    case XmlTypeCode.String:
                        generator = new GeneratorString(rFacets);
                        break;
                    case XmlTypeCode.Boolean:
                        generator = new GeneratorBoolean();
                        break;
                    case XmlTypeCode.Float:
                        generator = new GeneratorFloat(rFacets);
                        break;
                    case XmlTypeCode.Double:
                        generator = new GeneratorDouble(rFacets);
                        break;
                    case XmlTypeCode.AnyUri:
                        generator = new GeneratorAnyURI(rFacets);
                        break;
                    case XmlTypeCode.Integer:
                        generator = new GeneratorInteger(rFacets);
                        break;
                    case XmlTypeCode.Decimal:
                        generator = new GeneratorDecimal(rFacets);
                        break;
                    case XmlTypeCode.NonPositiveInteger:
                        generator = new GeneratorNonPositiveInteger(rFacets);
                        break;
                    case XmlTypeCode.NegativeInteger:
                        generator = new GeneratorNegativeInteger(rFacets);
                        break;
                    case XmlTypeCode.Long:
                        generator = new GeneratorLong(rFacets);
                        break;
                    case XmlTypeCode.Int:
                        generator = new GeneratorInt(rFacets);
                        break;
                    case XmlTypeCode.Short:
                        generator = new GeneratorShort(rFacets);
                        break;
                    case XmlTypeCode.Byte:
                        generator = new GeneratorByte(rFacets);
                        break;
                    case XmlTypeCode.NonNegativeInteger:
                        generator = new GeneratorNonNegativeInteger(rFacets);
                        break;
                    case XmlTypeCode.UnsignedLong:
                        generator = new GeneratorUnsignedLong(rFacets);
                        break;
                    case XmlTypeCode.UnsignedInt:
                        generator = new GeneratorUnsignedInt(rFacets);
                        break;
                    case XmlTypeCode.UnsignedShort:
                        generator = new GeneratorUnsignedShort(rFacets);
                        break;
                    case XmlTypeCode.UnsignedByte:
                        generator = new GeneratorUnsignedByte(rFacets);
                        break;
                    case XmlTypeCode.PositiveInteger:
                        generator = new GeneratorPositiveInteger(rFacets);
                        break;
                    case XmlTypeCode.Duration:
                        generator = new GeneratorDuration(rFacets);
                        break;
                    case XmlTypeCode.DateTime:
                        generator = new GeneratorDateTime(rFacets);
                        break;
                    case XmlTypeCode.Date:
                        generator = new GeneratorDate(rFacets);
                        break;
                    case XmlTypeCode.GYearMonth:
                        generator = new GeneratorYearMonth(rFacets);
                        break;
                    case XmlTypeCode.GYear:
                        generator = new GeneratorYear(rFacets);
                        break;
                    case XmlTypeCode.GMonthDay:
                        generator = new GeneratorMonthDay(rFacets);
                        break;
                    case XmlTypeCode.GDay:
                        generator = new GeneratorDay(rFacets);
                        break;
                    case XmlTypeCode.GMonth:
                        generator = new GeneratorMonth(rFacets);
                        break;
                    case XmlTypeCode.Time:
                        generator = new GeneratorTime(rFacets);
                        break;
                    case XmlTypeCode.HexBinary:
                        generator = new GeneratorHexBinary(rFacets);
                        break;
                    case XmlTypeCode.Base64Binary:
                        generator = new GeneratorBase64Binary(rFacets);
                        break;
                    case XmlTypeCode.QName:
                        generator = new GeneratorQName(rFacets);
                        break;
                    case XmlTypeCode.Notation:
                        generator = new GeneratorNotation(rFacets);
                        break;
                    case XmlTypeCode.NormalizedString:
                        generator = new GeneratorNormalizedString(rFacets);
                        break;
                    case XmlTypeCode.Token:
                        generator = new GeneratorToken(rFacets);
                        break;
                    case XmlTypeCode.Language:
                        generator = new GeneratorLanguage(rFacets);
                        break;
                    case XmlTypeCode.NmToken:
                        generator = new GeneratorNMTOKEN(rFacets);
                        break;
                    case XmlTypeCode.Name:
                        generator = new GeneratorName(rFacets);
                        break;
                    case XmlTypeCode.NCName:
                        generator = new GeneratorNcName(rFacets);
                        break;
                    case XmlTypeCode.Id:
                        GeneratorID.CheckFacets(rFacets);
                        generator = GeneratorID;
                        break;
                    case XmlTypeCode.Idref:
                        GeneratorIDREF.CheckFacets(rFacets);
                        generator = GeneratorIDREF;
                        break;
                    default:
                        generator = AnyGenerator;
                        break;
                }
            }
            generator.SetDatatype(datatype);
            return generator;
        }

        private static XmlValueGenerator CreateListGenerator(XmlSchemaDatatype dtype, CompiledFacets facets, int listLength)
        {
            var itemType =
                (XmlSchemaDatatype)
                dtype.GetType()
                     .InvokeMember("itemType",
                                   BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance,
                                   null,
                                   dtype,
                                   null);
            var generatorList = new GeneratorList(facets) { ListLength = listLength };
            generatorList.AddGenerator(CreateGenerator(itemType, listLength));
            return generatorList;
        }

        private static XmlValueGenerator CreateUnionGenerator(XmlSchemaDatatype dtype, CompiledFacets facets, int listLength)
        {
            var memberTypes =
                (XmlSchemaSimpleType[])
                dtype.GetType()
                     .InvokeMember("types",
                                   BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance,
                                   null,
                                   dtype,
                                   null);
            var unionGenerator = new GeneratorUnion(facets);
            foreach (XmlSchemaSimpleType st1 in memberTypes)
            {
                unionGenerator.AddGenerator(CreateGenerator(st1.Datatype, listLength));
            }
            return unionGenerator;
        }

        private void SetDatatype(XmlSchemaDatatype datatype)
        {
            Datatype = datatype;
        }

        #endregion
    }

    internal class GeneratorAnyType : XmlValueGenerator
    {
        #region Fields

        private const string VALUE = "anyType";

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            return VALUE;
        }

        #endregion
    }

    internal class GeneratorAnySimpleType : XmlValueGenerator
    {
        #region Fields

        private const string VALUE = "anySimpleType";

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            return VALUE;
        }

        #endregion
    }

    internal class GeneratorFacetBase : XmlValueGenerator
    {
        #region Fields

        protected int Length = -1;
        protected int MaxLength = -1;
        protected int MinLength = -1;

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            return string.Empty;
        }

        protected object GetEnumerationValue()
        {
            Debug.Assert(AllowedValues != null);
            try
            {
                return AllowedValues[OccurNum++ % AllowedValues.Count];
            }
            catch (OverflowException)
            {
                OccurNum = 0;
                return AllowedValues[OccurNum++];
            }
        }

        protected void ProcessLengthFacet(ref StringBuilder genString, int index)
        {
            int pLength = genString.Length;
            int indexLen = index.ToString(CultureInfo.InvariantCulture).Length;
            int correctLen = Length - indexLen;
            if (pLength > correctLen)
            {
                genString.Remove(correctLen, pLength - correctLen);
            }
            else if (pLength < correctLen)
            {
                int addCount = correctLen - pLength;
                for (int i = 0; i < addCount; i++)
                {
                    genString.Append("_");
                }
            }
        }

        protected void ProcessMaxLengthFacet(ref StringBuilder genString, int index)
        {
            int pLength = genString.Length;
            int indexLen = index.ToString(CultureInfo.InvariantCulture).Length;
            int correctLen = MaxLength - indexLen;
            if (pLength > correctLen)
            {
                genString.Remove(correctLen, pLength - correctLen);
            }
        }

        protected void ProcessMinLengthFacet(ref StringBuilder genString, int index)
        {
            int pLength = genString.Length;
            int indexLen = index.ToString(CultureInfo.InvariantCulture).Length;
            int correctLen = MinLength - indexLen;
            if (pLength < correctLen)
            {
                int addCount = correctLen - pLength;
                for (int i = 0; i < addCount; i++)
                {
                    genString.Append("_");
                }
            }
        }

        #endregion

        #region Methods

        internal void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.Length) != 0)
                {
                    Length = genFacets.Length;
                }
                if ((flags & RestrictionFlags.MinLength) != 0)
                {
                    MinLength = genFacets.MinLength;
                }
                if ((flags & RestrictionFlags.MaxLength) != 0)
                {
                    MaxLength = genFacets.MaxLength;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
            }
        }

        #endregion
    }

    //End of class stringBase

    internal class GeneratorString : GeneratorFacetBase
    {
        #region Fields

        private int _endValue;
        private StringBuilder _genString;

        private const int STEP = 1;

        #endregion

        #region Ctor(s)

        protected GeneratorString()
        {
        }

        public GeneratorString(CompiledFacets rFacets)
        {
            if (rFacets != null)
            {
                CheckFacets(rFacets);
            }
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            /* --------------- VB - 11/12/2013 --------------- */
            /* Rimossa logica di valorizzazione di enumeratori */
            /* ----------------------------------------------- */
            //if(AllowedValues != null) {
            //    object enumValue = GetEnumerationValue();
            //    return enumValue.ToString();
            //}
            //else {
            if (_genString == null)
            {
                _genString = new StringBuilder(Prefix);
            }
            else
            {
                _genString.Append(Prefix);
            }
            try
            {
                _endValue = _endValue + STEP;
            }
            catch (OverflowException)
            {
                //reset
                _endValue = 1;
            }
            if (Length == -1 && MinLength == -1 && MaxLength == -1)
            {
                _genString.Append(_endValue);
            }
            else
            {
                if (Length != -1)
                {
                    // The length facet is set
                    ProcessLengthFacet(ref _genString, _endValue);
                    _genString.Append(_endValue);
                }
                else
                {
                    if (MinLength != -1)
                    {
                        ProcessMinLengthFacet(ref _genString, _endValue);
                    }
                    if (MaxLength != -1)
                    {
                        ProcessMaxLengthFacet(ref _genString, _endValue);
                    }
                    _genString.Append(_endValue);
                }
            }
            string result = _genString.ToString();
            _genString.Length = 0;
            return result;
        }

        #endregion
    }

    internal class GeneratorDecimal : XmlValueGenerator
    {
        #region Fields

        protected decimal increment;
        protected decimal maxBound = decimal.MaxValue;
        protected decimal minBound = decimal.MinValue;
        protected decimal startValue = 1;
        protected decimal step = 0.1m;

        private int _stateStep = 1;

        #endregion

        #region Ctor(s)

        public GeneratorDecimal(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        protected GeneratorDecimal()
        {
        }

        #endregion

        #region Public Properties

        public decimal StartValue
        {
            set { startValue = value; }
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            decimal result = 0;
            if (AllowedValues != null)
            {
                try
                {
                    result = (decimal)AllowedValues[OccurNum++ % AllowedValues.Count];
                }
                catch (OverflowException)
                {
                    OccurNum = 0;
                    result = (decimal)AllowedValues[OccurNum++];
                }
            }
            else
            {
                try
                {
                    AddSubtractState state = States[OccurNum % States.Length];
                    switch (state)
                    {
                        case AddSubtractState.StartPlusInc:
                            result = startValue + increment;
                            break;

                        case AddSubtractState.MinPlusInc:
                            result = minBound + increment;
                            break;

                        case AddSubtractState.MaxMinusInc:
                            result = maxBound - increment;
                            if (_stateStep == 2)
                            {
                                increment = increment + step;
                            }
                            break;

                        case AddSubtractState.StartMinusInc:
                            increment = increment + step;
                            result = startValue - increment;
                            break;

                        default:
                            Debug.Assert(false);
                            break;
                    }
                    OccurNum = OccurNum + _stateStep;
                }
                catch (OverflowException)
                {
                    result = ResetState();
                }
                if (result >= maxBound)
                {
                    result = maxBound;
                }
                else if (result <= minBound)
                {
                    result = minBound;
                }
            }
            return result.ToString(null, NumberFormatInfo.InvariantInfo);
        }

        #endregion

        #region Methods

        protected void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.MaxInclusive) != 0)
                {
                    maxBound = (decimal)Convert.ChangeType(genFacets.MaxInclusive, typeof(decimal));
                }
                if ((flags & RestrictionFlags.MaxExclusive) != 0)
                {
                    maxBound = (decimal)Convert.ChangeType(genFacets.MaxExclusive, typeof(decimal)) - 1;
                }
                if ((flags & RestrictionFlags.MinInclusive) != 0)
                {
                    startValue = (decimal)Convert.ChangeType(genFacets.MinInclusive, typeof(decimal));
                    minBound = startValue;
                }
                if ((flags & RestrictionFlags.MinExclusive) != 0)
                {
                    startValue = (decimal)Convert.ChangeType(genFacets.MinExclusive, typeof(decimal)) + 1;
                    minBound = startValue;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
                if ((flags & RestrictionFlags.TotalDigits) != 0)
                {
                    decimal totalDigitsValue = (decimal)Math.Pow(10, genFacets.TotalDigits) - 1;
                    if (totalDigitsValue <= maxBound)
                    {
                        maxBound = totalDigitsValue;
                        minBound = 0 - maxBound;
                    }
                }
                if ((flags & RestrictionFlags.FractionDigits) != 0 && genFacets.FractionDigits > 0)
                {
                    if ((flags & RestrictionFlags.TotalDigits) != 0)
                    {
                        int range = genFacets.TotalDigits - genFacets.FractionDigits;
                        double integralPart = Math.Pow(10, range) - 1;
                        double fractionPart = integralPart / Math.Pow(10, range);
                        maxBound = (decimal)(integralPart + fractionPart);
                        minBound = 0 - maxBound;
                        step = (decimal)(1 / Math.Pow(10, range));
                    }
                }
                if (maxBound <= 0)
                {
                    startValue = maxBound;
                    OccurNum++;
                    _stateStep = 2;
                }
                if (startValue == minBound)
                {
                    _stateStep = 2;
                }
            }
        }

        private decimal ResetState()
        {
            increment = 0;
            if (startValue == maxBound)
            {
                OccurNum = 1;
                _stateStep = 2;
            }
            if (startValue == minBound)
            {
                OccurNum = 0;
                _stateStep = 2;
            }
            return startValue;
        }

        #endregion
    }

    internal class GeneratorInteger : GeneratorDecimal
    {
        #region Ctor(s)

        public GeneratorInteger(CompiledFacets rFacets)
            : base(rFacets)
        {
            step = 1;
        }

        protected GeneratorInteger()
        {
            step = 1;
        }

        #endregion
    }

    internal class GeneratorNonPositiveInteger : GeneratorInteger
    {
        #region Ctor(s)

        protected GeneratorNonPositiveInteger()
        {
        }

        public GeneratorNonPositiveInteger(CompiledFacets rFacets)
        {
            startValue = 0;
            increment = 1;
            maxBound = 0;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorNegativeInteger : GeneratorNonPositiveInteger
    {
        #region Ctor(s)

        public GeneratorNegativeInteger(CompiledFacets rFacets)
        {
            startValue = -1;
            maxBound = -1;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorLong : GeneratorInteger
    {
        #region Ctor(s)

        protected GeneratorLong()
        {
            maxBound = 9223372036854775807;
            minBound = -9223372036854775807;
        }

        public GeneratorLong(CompiledFacets rFacets)
        {
            maxBound = 9223372036854775807;
            minBound = -9223372036854775807;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorInt : GeneratorLong
    {
        #region Ctor(s)

        public GeneratorInt()
        {
            maxBound = 2147483647;
            minBound = -2147483647;
        }

        public GeneratorInt(CompiledFacets rFacets)
        {
            maxBound = 2147483647;
            minBound = -2147483647;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorShort : GeneratorInt
    {
        #region Ctor(s)

        protected GeneratorShort()
        {
            maxBound = 32767;
            minBound = -32768;
        }

        public GeneratorShort(CompiledFacets rFacets)
        {
            maxBound = 32767;
            minBound = -32768;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorByte : GeneratorShort
    {
        #region Ctor(s)

        public GeneratorByte(CompiledFacets rFacets)
        {
            maxBound = 127;
            minBound = -128;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorNonNegativeInteger : GeneratorInteger
    {
        #region Ctor(s)

        protected GeneratorNonNegativeInteger()
        {
            startValue = 0;
            minBound = 0;
        }

        public GeneratorNonNegativeInteger(CompiledFacets rFacets)
        {
            startValue = 0;
            minBound = 0;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorUnsignedLong : GeneratorNonNegativeInteger
    {
        #region Ctor(s)

        protected GeneratorUnsignedLong()
        {
        }

        public GeneratorUnsignedLong(CompiledFacets rFacets)
        {
            maxBound = 18446744073709551615;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorUnsignedInt : GeneratorUnsignedLong
    {
        #region Ctor(s)

        protected GeneratorUnsignedInt()
        {
        }

        public GeneratorUnsignedInt(CompiledFacets rFacets)
        {
            maxBound = 4294967295;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorUnsignedShort : GeneratorUnsignedInt
    {
        #region Ctor(s)

        protected GeneratorUnsignedShort()
        {
        }

        public GeneratorUnsignedShort(CompiledFacets rFacets)
        {
            maxBound = 65535;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorUnsignedByte : GeneratorUnsignedShort
    {
        #region Ctor(s)

        public GeneratorUnsignedByte()
        {
        }

        public GeneratorUnsignedByte(CompiledFacets rFacets)
        {
            maxBound = 255;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorPositiveInteger : GeneratorNonNegativeInteger
    {
        #region Ctor(s)

        public GeneratorPositiveInteger(CompiledFacets rFacets)
        {
            startValue = 1;
            minBound = 1;
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorBoolean : XmlValueGenerator
    {
        #region Public Methods and Operators

        public override string GenerateValue()
        {
            if ((OccurNum & 0x1) == 0)
            {
                OccurNum = 1;
                return "true";
            }
            OccurNum = 0;
            return "false";
        }

        #endregion
    }

    internal class GeneratorDouble : XmlValueGenerator
    {
        #region Fields

        protected double MaxBound = double.MaxValue;
        protected double MinBound = double.MinValue;
        protected double StartValue = 1;
        protected const double STEP = 1.1F;

        private double _increment;
        private int _stateStep = 1;

        #endregion

        #region Ctor(s)

        public GeneratorDouble()
        {
        }

        public GeneratorDouble(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.MaxInclusive) != 0)
                {
                    MaxBound = (double)genFacets.MaxInclusive;
                }
                if ((flags & RestrictionFlags.MaxExclusive) != 0)
                {
                    MaxBound = (double)genFacets.MaxExclusive - 1;
                }
                if ((flags & RestrictionFlags.MinInclusive) != 0)
                {
                    StartValue = (double)genFacets.MinInclusive;
                    MinBound = StartValue;
                }
                if ((flags & RestrictionFlags.MinExclusive) != 0)
                {
                    StartValue = (double)genFacets.MinExclusive + 1;
                    MinBound = StartValue;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
                if (MaxBound <= 0)
                {
                    StartValue = MaxBound;
                    OccurNum++;
                    _stateStep = 2;
                }
                if (StartValue.IsNearlyEqual(MinBound))
                {
                    _stateStep = 2;
                }
            }
        }

        public override string GenerateValue()
        {
            double result = 0;
            if (AllowedValues != null)
            {
                try
                {
                    result = (double)AllowedValues[OccurNum++ % AllowedValues.Count];
                }
                catch (OverflowException)
                {
                    OccurNum = 0;
                    result = (double)AllowedValues[OccurNum++];
                }
            }
            else
            {
                try
                {
                    AddSubtractState state = States[OccurNum % States.Length];
                    switch (state)
                    {
                        case AddSubtractState.StartPlusInc:
                            result = StartValue + _increment;
                            break;

                        case AddSubtractState.MinPlusInc:
                            result = MinBound + _increment;
                            break;

                        case AddSubtractState.MaxMinusInc:
                            result = MaxBound - _increment;
                            if (_stateStep == 2)
                            {
                                _increment = _increment + STEP;
                            }
                            break;

                        case AddSubtractState.StartMinusInc:
                            _increment = _increment + STEP; //stateStep is 1 or 2, we need to increment now
                            result = StartValue - _increment;
                            break;

                        default:
                            Debug.Assert(false);
                            break;
                    }
                    OccurNum = OccurNum + _stateStep;
                }
                catch (OverflowException)
                {
                    //reset
                    result = ResetState();
                }
                if (result > MaxBound)
                {
                    result = MaxBound;
                }
                else if (result < MinBound)
                {
                    result = MinBound;
                }
            }
            return XmlConvert.ToString(result);
        }

        #endregion

        #region Methods

        private double ResetState()
        {
            _increment = 0F;
            if (StartValue.IsNearlyEqual(MaxBound))
            {
                OccurNum = 1;
                _stateStep = 2;
            }
            
            if (StartValue.IsNearlyEqual(MinBound))
            {
                OccurNum = 0;
                _stateStep = 2;
            }
            return StartValue;
        }

        #endregion
    }

    internal class GeneratorFloat : XmlValueGenerator
    {
        #region Constants

        private const float STEP = 1.1F;

        #endregion

        #region Fields

        private float _increment;

        private float _maxBound = float.MaxValue;

        private float _minBound = float.MinValue;

        private float _startValue = 1;

        private int _stateStep = 1;

        #endregion

        #region Ctor(s)

        public GeneratorFloat(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.MaxInclusive) != 0)
                {
                    _maxBound = (float)genFacets.MaxInclusive;
                }
                if ((flags & RestrictionFlags.MaxExclusive) != 0)
                {
                    _maxBound = (float)genFacets.MaxExclusive - 1;
                }
                if ((flags & RestrictionFlags.MinInclusive) != 0)
                {
                    _startValue = (float)genFacets.MinInclusive;
                    _minBound = _startValue;
                }
                if ((flags & RestrictionFlags.MinExclusive) != 0)
                {
                    _startValue = (float)genFacets.MinExclusive + 1;
                    _minBound = _startValue;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
                if (_maxBound <= 0)
                {
                    _startValue = _maxBound;
                    OccurNum++;
                    _stateStep = 2;
                }
                if (_startValue.IsNearlyEqual(_minBound))
                {
                    _stateStep = 2;
                }
            }
        }

        public override string GenerateValue()
        {
            float result = 0;
            if (AllowedValues != null)
            {
                try
                {
                    result = (float)AllowedValues[OccurNum++ % AllowedValues.Count];
                }
                catch (OverflowException)
                {
                    OccurNum = 0;
                    result = (float)AllowedValues[OccurNum++];
                }
            }
            else
            {
                try
                {
                    AddSubtractState state = States[OccurNum % States.Length];
                    switch (state)
                    {
                        case AddSubtractState.StartPlusInc:
                            result = _startValue + _increment;
                            break;

                        case AddSubtractState.MinPlusInc:
                            result = _minBound + _increment;
                            break;

                        case AddSubtractState.MaxMinusInc:
                            result = _maxBound - _increment;
                            if (_stateStep == 2)
                            {
                                _increment = _increment + STEP;
                            }
                            break;

                        case AddSubtractState.StartMinusInc:
                            _increment = _increment + STEP; //stateStep is 1 or 2, we need to increment now
                            result = _startValue - _increment;
                            break;

                        default:
                            Debug.Assert(false);
                            break;
                    }
                    OccurNum = OccurNum + _stateStep;
                }
                catch (OverflowException)
                {
                    //reset
                    result = ResetState();
                }
                if (result > _maxBound)
                {
                    result = _maxBound;
                }
                else if (result < _minBound)
                {
                    result = _minBound;
                }
            }
            return XmlConvert.ToString(result);
        }

        #endregion

        #region Methods

        private float ResetState()
        {
            _increment = 0F;
            if (_startValue.IsNearlyEqual(_maxBound))
            {
                OccurNum = 1;
                _stateStep = 2;
            }
            if (_startValue.IsNearlyEqual(_minBound))
            {
                OccurNum = 0;
                _stateStep = 2;
            }
            return _startValue;
        }

        #endregion
    }

    internal class GeneratorDuration : XmlValueGenerator
    {
        #region Fields

        private readonly TimeSpan _endValue = new TimeSpan(1, 0, 0, 0);
        private readonly TimeSpan _step = XmlConvert.ToTimeSpan("P1Y");

        private TimeSpan _increment = new TimeSpan(0, 0, 0, 0);
        private TimeSpan _maxBound = new TimeSpan(TimeSpan.MaxValue.Days,
                                                  TimeSpan.MaxValue.Hours,
                                                  TimeSpan.MaxValue.Minutes,
                                                  TimeSpan.MaxValue.Seconds,
                                                  TimeSpan.MaxValue.Milliseconds);
        private TimeSpan _minBound = new TimeSpan(TimeSpan.MinValue.Days,
                                                  TimeSpan.MinValue.Hours,
                                                  TimeSpan.MinValue.Minutes,
                                                  TimeSpan.MinValue.Seconds,
                                                  TimeSpan.MinValue.Milliseconds);
        private TimeSpan _startValue = XmlConvert.ToTimeSpan("P1Y1M1DT1H1M1S");
        private int _stateStep = 1;

        #endregion

        #region Ctor(s)

        public GeneratorDuration(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.MaxInclusive) != 0)
                {
                    _maxBound = (TimeSpan)genFacets.MaxInclusive;
                }
                if ((flags & RestrictionFlags.MaxExclusive) != 0)
                {
                    _maxBound = (TimeSpan)genFacets.MaxExclusive - _endValue;
                }
                if ((flags & RestrictionFlags.MinInclusive) != 0)
                {
                    _startValue = (TimeSpan)genFacets.MinInclusive;
                    _minBound = _startValue;
                }
                if ((flags & RestrictionFlags.MinExclusive) != 0)
                {
                    _startValue = (TimeSpan)genFacets.MinExclusive + _endValue;
                    _minBound = _startValue;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
                if (TimeSpan.Compare(_maxBound, TimeSpan.Zero) == -1)
                {
                    _startValue = _maxBound;
                    OccurNum++;
                    _stateStep = 2;
                }
                if (TimeSpan.Compare(_minBound, _startValue) == 0)
                {
                    _stateStep = 2;
                }
            }
        }

        public override string GenerateValue()
        {
            TimeSpan result = TimeSpan.Zero;
            if (AllowedValues != null)
            {
                try
                {
                    result = (TimeSpan)AllowedValues[OccurNum++ % AllowedValues.Count];
                }
                catch (OverflowException)
                {
                    OccurNum = 0;
                    result = (TimeSpan)AllowedValues[OccurNum++];
                }
            }
            else
            {
                try
                {
                    AddSubtractState state = States[OccurNum % States.Length];
                    switch (state)
                    {
                        case AddSubtractState.StartPlusInc:
                            result = _startValue + _increment;
                            break;

                        case AddSubtractState.MinPlusInc:
                            result = _minBound + _increment;
                            break;

                        case AddSubtractState.MaxMinusInc:
                            result = _maxBound - _increment;
                            if (_stateStep == 2)
                            {
                                _increment = _increment + _step;
                            }
                            break;

                        case AddSubtractState.StartMinusInc:
                            _increment = _increment + _step;
                            result = _startValue - _increment;
                            break;

                        default:
                            Debug.Assert(false);
                            break;
                    }
                    OccurNum = OccurNum + _stateStep;
                }
                catch (OverflowException)
                {
                    result = ResetState();
                }
                if (result > _maxBound)
                {
                    result = _maxBound;
                }
                else if (result < _minBound)
                {
                    result = _minBound;
                }
            }
            return XmlConvert.ToString(result);
        }

        #endregion

        #region Methods

        private TimeSpan ResetState()
        {
            _increment = TimeSpan.Zero;
            OccurNum = 0;
            if (TimeSpan.Compare(_maxBound, _startValue) == 0)
            {
                OccurNum++;
                _stateStep = 2;
            }
            if (TimeSpan.Compare(_minBound, _startValue) == 0)
            {
                _stateStep = 2;
            }
            return _startValue;
        }

        #endregion
    }
    
    internal class GeneratorDateTime : XmlValueGenerator
    {
        #region Fields

        protected DateTime MaxBound = DateTime.MaxValue;
        protected DateTime MinBound = DateTime.MinValue;
        protected DateTime StartValue = new DateTime(1900, 1, 1, 1, 1, 1);
        protected TimeSpan Step = XmlConvert.ToTimeSpan("P32D");

        private TimeSpan _increment;
        private int _stateStep = 1;

        #endregion

        #region Ctor(s)

        protected GeneratorDateTime()
        {
        }

        public GeneratorDateTime(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        protected void CheckFacets(CompiledFacets genFacets)
        {
            if (genFacets != null)
            {
                RestrictionFlags flags = genFacets.Flags;
                if ((flags & RestrictionFlags.MaxInclusive) != 0)
                {
                    MaxBound = (DateTime)genFacets.MaxInclusive;
                }
                if ((flags & RestrictionFlags.MaxExclusive) != 0)
                {
                    MaxBound = ((DateTime)genFacets.MaxExclusive).Subtract(Step);
                }
                if ((flags & RestrictionFlags.MinInclusive) != 0)
                {
                    StartValue = (DateTime)genFacets.MinInclusive;
                    MinBound = StartValue;
                }
                if ((flags & RestrictionFlags.MinExclusive) != 0)
                {
                    StartValue = ((DateTime)genFacets.MinExclusive).Add(Step);
                    MinBound = StartValue;
                }
                if ((flags & RestrictionFlags.Enumeration) != 0)
                {
                    AllowedValues = genFacets.Enumeration;
                }
                if (DateTime.Compare(StartValue, MaxBound) == 0)
                {
                    OccurNum++;
                    _stateStep = 2;
                }
                if (DateTime.Compare(StartValue, MinBound) == 0)
                {
                    _stateStep = 2;
                }
            }
        }

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result, XmlDateTimeSerializationMode.Local);
        }

        #endregion

        #region Methods

        protected DateTime GenerateDate()
        {
            if (AllowedValues != null)
            {
                try
                {
                    return (DateTime)AllowedValues[OccurNum++ % AllowedValues.Count];
                }
                catch (OverflowException)
                {
                    OccurNum = 0;
                    return (DateTime)AllowedValues[OccurNum++];
                }
            }
            DateTime result = DateTime.UtcNow;
            try
            {
                AddSubtractState state = States[OccurNum % States.Length];
                switch (state)
                {
                    case AddSubtractState.StartPlusInc:
                        result = StartValue.Add(_increment);
                        break;

                    case AddSubtractState.MinPlusInc:
                        result = MinBound.Add(_increment);
                        break;

                    case AddSubtractState.MaxMinusInc:
                        result = MaxBound.Subtract(_increment);
                        if (_stateStep == 2)
                        {
                            _increment = _increment + Step;
                        }
                        break;

                    case AddSubtractState.StartMinusInc:
                        _increment = _increment + Step;
                        result = StartValue.Subtract(_increment);
                        break;

                    default:
                        Debug.Assert(false);
                        break;
                }
                OccurNum = OccurNum + _stateStep;
            }
            catch (ArgumentOutOfRangeException)
            {
                result = ResetState();
            }
            if (result >= MaxBound)
            {
                result = MaxBound;
            }
            else if (result <= MinBound)
            {
                result = MinBound;
            }
            return result;
        }

        private DateTime ResetState()
        {
            _increment = TimeSpan.Zero;
            OccurNum = 0;
            if (DateTime.Compare(StartValue, MaxBound) == 0)
            {
                OccurNum++;
                _stateStep = 2;
            }
            if (DateTime.Compare(StartValue, MinBound) == 0)
            {
                _stateStep = 2;
            }
            return StartValue;
        }

        #endregion
    }

    internal class GeneratorDate : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorDate(CompiledFacets rFacets)
            : base(rFacets)
        {
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result.Date, "yyyy-MM-dd");
        }

        #endregion
    }

    internal class GeneratorYearMonth : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorYearMonth(CompiledFacets rFacets)
        {
            Step = XmlConvert.ToTimeSpan("P32D");
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result.Date, "yyyy-MM");
        }

        #endregion
    }

    internal class GeneratorYear : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorYear(CompiledFacets rFacets)
        {
            Step = XmlConvert.ToTimeSpan("P380D");
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result.Date, "yyyy");
        }

        #endregion
    }

    internal class GeneratorMonthDay : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorMonthDay(CompiledFacets rFacets)
        {
            Step = XmlConvert.ToTimeSpan("P1M5D");
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result.Date, "--MM-dd");
        }

        #endregion
    }

    internal class GeneratorDay : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorDay(CompiledFacets rFacets)
            : base(rFacets)
        {
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            DateTime result = GenerateDate();
            return XmlConvert.ToString(result.Date, "---dd");
        }

        #endregion
    }

    internal class GeneratorMonth : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorMonth(CompiledFacets rFacets)
        {
            Step = XmlConvert.ToTimeSpan("P32D");
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            GenerateDate();
            return XmlConvert.ToString(GenerateDate().Date, "--MM--");
        }

        #endregion
    }

    internal class GeneratorTime : GeneratorDateTime
    {
        #region Ctor(s)

        public GeneratorTime(CompiledFacets rFacets)
        {
            Step = XmlConvert.ToTimeSpan("PT1M30S");
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            return XmlConvert.ToString(GenerateDate(), "HH:mm:ss");
        }

        #endregion
    }

    internal class GeneratorHexBinary : GeneratorFacetBase
    {
        #region Fields

        private readonly GeneratorInteger _binGen = new GeneratorInt();

        #endregion

        #region Ctor(s)

        public GeneratorHexBinary(CompiledFacets rFacets)
        {
            _binGen.StartValue = 4023;
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            if (AllowedValues != null)
            {
                object enumValue = GetEnumerationValue();
                return (string)Datatype.ChangeType(enumValue, TypeOfString);
            }
            var binNo = (int)Convert.ChangeType(_binGen.GenerateValue(), typeof(int));
            var str = new StringBuilder(binNo.ToString("X4"));
            if (Length == -1 && MinLength == -1 && MaxLength == -1)
            {
                return str.ToString();
            }
            if (Length != -1)
            {
                ProcessLengthFacet(ref str);
            }
            else
            {
                ProcessMinMaxLengthFacet(ref str);
            }
            return str.ToString();
        }

        #endregion

        #region Methods

        private void ProcessLengthFacet(ref StringBuilder str)
        {
            int pLength = str.Length;
            if (pLength % 2 != 0)
            {
                throw new Exception("Total length of binary data should be even");
            }
            int correctLen = pLength / 2;

            if (correctLen > Length)
            {
                str.Remove(Length, (correctLen - Length) * 2);
            }
            else if (correctLen < Length)
            {
                int addCount = Length - correctLen;
                for (int i = 0; i < addCount; i++)
                {
                    str.Append("0A");
                }
            }
        }

        private void ProcessMinMaxLengthFacet(ref StringBuilder str)
        {
            int pLength = str.Length;
            if (pLength % 2 != 0)
            {
                throw new Exception("Total length of binary data should be even");
            }
            int correctLen = pLength / 2;
            if (MinLength != -1)
            {
                if (correctLen < MinLength)
                {
                    int addCount = MinLength - correctLen;
                    for (int i = 0; i < addCount; i++)
                    {
                        str.Append("0A");
                    }
                }
            }
            else
            {
                if (correctLen > MaxLength)
                {
                    str.Remove(MaxLength, (correctLen - MaxLength) * 2);
                }
            }
        }

        #endregion
    }

    internal class GeneratorBase64Binary : GeneratorFacetBase
    {
        #region Ctor(s)

        public GeneratorBase64Binary(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            if (AllowedValues != null)
            {
                object enumValue = GetEnumerationValue();
                if (enumValue != null)
                {
                    return Convert.ToBase64String(enumValue as byte[]);
                }
            }
            return string.Empty;
        }

        #endregion
    }

    internal class GeneratorQName : GeneratorString
    {
        #region Ctor(s)

        protected GeneratorQName()
        {
        }

        public GeneratorQName(CompiledFacets rFacets)
        {
            Prefix = "qname";
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            string result = base.GenerateValue();
            return result.Length == 1 ? new string(Prefix[0], 1) : result;
        }

        #endregion
    }

    internal class GeneratorNotation : GeneratorQName
    {
        #region Ctor(s)

        public GeneratorNotation(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorNormalizedString : GeneratorString
    {
        #region Ctor(s)

        protected GeneratorNormalizedString()
        {
        }

        public GeneratorNormalizedString(CompiledFacets rFacets)
            : base(rFacets)
        {
        }

        #endregion
    }

    internal class GeneratorToken : GeneratorNormalizedString
    {
        #region Ctor(s)

        protected GeneratorToken()
        {
        }

        public GeneratorToken(CompiledFacets rFacets)
        {
            Prefix = "Token";
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorLanguage : GeneratorString
    {
        #region Static Fields

        private static readonly string[] languageList = new[] { "en", "fr", "de", "da", "el", "it", "en-US" };

        #endregion

        #region Ctor(s)

        public GeneratorLanguage(CompiledFacets rFacets)
            : base(rFacets)
        {
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            return AllowedValues != null ? base.GenerateValue() : languageList[OccurNum++ % languageList.Length];
        }

        #endregion
    }

    internal class GeneratorNMTOKEN : GeneratorToken
    {
        #region Ctor(s)

        public GeneratorNMTOKEN()
        {
        }

        public GeneratorNMTOKEN(CompiledFacets rFacets)
            : base(rFacets)
        {
        }

        #endregion
    }

    internal sealed class GeneratorName : GeneratorString
    {
        #region Ctor(s)

        public GeneratorName(CompiledFacets rFacets)
        {
            Prefix = "Name";
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal sealed class GeneratorNcName : GeneratorString
    {
        #region Ctor(s)

        public GeneratorNcName(CompiledFacets rFacets)
        {
            Prefix = "NcName";
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal sealed class GeneratorID : GeneratorString
    {
        #region Ctor(s)

        public GeneratorID()
        {
            Prefix = "ID";
        }

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            if (IDRef)
            {
                IDRef = false;
                return (string)IDList[IDCnt - 1];
            }
            string id = base.GenerateValue();
            IDList.Add(id);
            return (string)IDList[IDCnt++];
        }

        #endregion
    }

    internal class GeneratorIDREF : GeneratorString
    {
        #region Fields

        private int _refCnt;

        #endregion

        #region Public Methods and Operators

        public override string GenerateValue()
        {
            if (IDList.Count == 0)
            {
                GeneratorID.GenerateValue();
                IDRef = true;
            }
            if (_refCnt >= IDList.Count)
            {
                _refCnt = _refCnt - IDList.Count;
            }
            return (string)IDList[_refCnt++];
        }

        #endregion
    }

    internal sealed class GeneratorAnyURI : GeneratorString
    {
        #region Ctor(s)

        public GeneratorAnyURI(CompiledFacets rFacets)
        {
            Prefix = "http://uri";
            CheckFacets(rFacets);
        }

        #endregion
    }

    internal class GeneratorUnion : GeneratorFacetBase
    {
        #region Fields

        private readonly ArrayList _unionGens = new ArrayList();

        #endregion

        #region Ctor(s)

        public GeneratorUnion()
        {
        }

        public GeneratorUnion(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Properties

        internal ArrayList Generators
        {
            get { return _unionGens; }
        }

        #endregion

        #region Public Methods and Operators

        public override void AddGenerator(XmlValueGenerator genr)
        {
            _unionGens.Add(genr);
        }

        public override string GenerateValue()
        {
            if (AllowedValues != null)
            {
                object enumValue = GetEnumerationValue();
                object typedValue = CompiledFacets.XsdSimpleValueType.InvokeMember("typedValue",
                                                                                   BindingFlags.GetField |
                                                                                   BindingFlags.NonPublic |
                                                                                   BindingFlags.Instance,
                                                                                   null,
                                                                                   enumValue,
                                                                                   null);
                return (string)Datatype.ChangeType(typedValue, TypeOfString);
            }
            if (_unionGens.Count > 0)
            {
                var genr = (XmlValueGenerator)(_unionGens[OccurNum % _unionGens.Count]);
                genr.Prefix = Prefix;
                OccurNum = OccurNum + 1;
                return genr.GenerateValue();
            }
            return string.Empty;
        }

        #endregion
    }

    internal class GeneratorList : GeneratorFacetBase
    {
        #region Fields

        private XmlValueGenerator _generator;
        private int _listLength;
        private StringBuilder _resultBuilder;

        #endregion

        #region Ctor(s)

        public GeneratorList()
        {
        }

        public GeneratorList(CompiledFacets rFacets)
        {
            CheckFacets(rFacets);
        }

        #endregion

        #region Public Properties

        public int ListLength
        {
            get { return _listLength; }
            set { _listLength = value; }
        }

        #endregion

        #region Public Methods and Operators

        public override void AddGenerator(XmlValueGenerator valueGenr)
        {
            _generator = valueGenr;
        }

        public override string GenerateValue()
        {
            if (_resultBuilder == null)
            {
                _resultBuilder = new StringBuilder();
            }
            else
            {
                //Clear old value
                _resultBuilder.Length = 0;
            }
            if (AllowedValues != null)
            {
                object enumValue = GetEnumerationValue();
                return (string)Datatype.ChangeType(enumValue, TypeOfString);
            }
            _generator.Prefix = Prefix;
            int noItems = _listLength;
            if (Length != -1)
            {
                noItems = Length;
            }
            else if (MinLength != -1)
            {
                noItems = MinLength;
            }
            else if (MaxLength != -1)
            {
                noItems = MaxLength;
            }
            for (int i = 0; i < noItems; i++)
            {
                _resultBuilder.Append(_generator.GenerateValue());
                _resultBuilder.Append(" ");
            }
            return _resultBuilder.ToString();
        }

        #endregion
    }
}